#include "data_manager.h"
#include "ns3/log.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <filesystem>
#include <regex>
#include <algorithm>
#include <iomanip>

namespace fs = std::filesystem;

namespace ns3 {

NS_LOG_COMPONENT_DEFINE("DataManager");

DataManager::DataManager()
  : m_dataPath("/home/xixi/SAGIN/ns-allinone-3.42/ns-3.42/scratch/simulation/positions")
{
  NS_LOG_FUNCTION(this);
}

DataManager::~DataManager() 
{
  NS_LOG_FUNCTION(this);
}

bool DataManager::Initialize() 
{
  NS_LOG_FUNCTION(this);
  
  // 加载车辆轨迹数据
  if (!LoadVehicleData()) {
    NS_LOG_ERROR("加载车辆数据失败");
    return false;
  }
  
  // 加载地面基站位置数据
  if (!LoadGroundStationData()) {
    NS_LOG_ERROR("加载地面基站数据失败");
    return false;
  }
  
  // 加载卫星位置数据
  if (!LoadSatelliteData()) {
    NS_LOG_ERROR("加载卫星数据失败");
    return false;
  }
  
  NS_LOG_INFO("数据管理器初始化成功. 找到 " 
             << m_vehicleData.size() << " 辆车, "
             << m_groundStationPositions.size() << " 个地面基站, "
             << m_satellitePositions.size() << " 个卫星");
  
  return true;
}

std::vector<uint32_t> DataManager::GetAllVehicleIds() const 
{
  std::vector<uint32_t> vehicleIds;
  vehicleIds.reserve(m_vehicleData.size());
  
  for (const auto& entry : m_vehicleData) {
    vehicleIds.push_back(entry.first);
  }
  
  return vehicleIds;
}

std::vector<VehicleData> DataManager::GetVehicleTrajectory(uint32_t vehicleId) const 
{
  auto it = m_vehicleData.find(vehicleId);
  if (it != m_vehicleData.end()) {
    return it->second;
  }
  return std::vector<VehicleData>();
}

std::vector<NodePositionData> DataManager::GetGroundStationPositions() const 
{
  return m_groundStationPositions;
}

std::vector<NodePositionData> DataManager::GetSatellitePositions() const 
{
  return m_satellitePositions;
}

bool DataManager::SavePerformanceData(uint32_t vehicleId, 
                                      uint32_t nodeId, 
                                      const std::string& nodeType,
                                      const std::map<std::string, double>& data, 
                                      const std::string& outputDir) const 
{
  NS_LOG_FUNCTION(this << vehicleId << nodeId << nodeType);
  
  // 构造输出文件名
  std::string filename = outputDir + "/vehicle_" + std::to_string(vehicleId) + "_" 
                      + nodeType + "_" + std::to_string(nodeId) + ".csv";
  
  std::ofstream outFile(filename);
  if (!outFile) {
    NS_LOG_ERROR("无法打开输出文件 " << filename);
    return false;
  }
  
  // 写入头行
  outFile << "vehicle_id,node_id,node_type";
  for (const auto& entry : data) {
    outFile << "," << entry.first;
  }
  outFile << std::endl;
  
  // 写入数据行
  outFile << vehicleId << "," << nodeId << "," << nodeType;
  for (const auto& entry : data) {
    outFile << "," << std::fixed << std::setprecision(6) << entry.second;
  }
  outFile << std::endl;
  
  outFile.close();
  NS_LOG_INFO("性能数据已保存到 " << filename);
  
  return true;
}

bool DataManager::LoadVehicleData() 
{
  NS_LOG_FUNCTION(this);
  
  std::string vehiclesDir = m_dataPath + "/vehicles";
  
  try {
    // 检查目录是否存在
    if (!fs::exists(vehiclesDir) || !fs::is_directory(vehiclesDir)) {
      NS_LOG_ERROR("车辆数据目录不存在: " << vehiclesDir);
      return false;
    }
    
    // 遍历目录中的车辆数据文件
    for (const auto& entry : fs::directory_iterator(vehiclesDir)) {
      if (!entry.is_regular_file() || entry.path().extension() != ".csv") {
        continue;
      }
      
      // 解析文件名，提取车辆ID
      std::string filename = entry.path().filename().string();
      uint32_t vehicleId = ParseVehicleId(filename);
      if (vehicleId == 0) {
        continue;
      }
      
      // 读取车辆数据
      std::ifstream file(entry.path());
      if (!file) {
        NS_LOG_WARN("无法打开车辆数据文件: " << entry.path().string());
        continue;
      }
      
      std::vector<VehicleData> trajectory;
      std::string line;
      bool isFirstLine = true;
      
      while (std::getline(file, line)) {
        // 跳过注释行和标题行
        if (line.empty() || line[0] == '#' || line[0] == '/' || isFirstLine) {
          isFirstLine = false;
          continue;
        }
        
        std::istringstream iss(line);
        std::string token;
        std::vector<std::string> tokens;
        
        // 分割CSV行
        while (std::getline(iss, token, ',')) {
          tokens.push_back(token);
        }
        
        // 确保有足够的数据列
        if (tokens.size() >= 6) {
          VehicleData data;
          data.id = std::stoul(tokens[0]);
          data.position.x = std::stod(tokens[1]);
          data.position.y = std::stod(tokens[2]);
          data.position.z = std::stod(tokens[3]);
          data.time = std::stod(tokens[4]);
          data.speed = std::stod(tokens[5]);
          
          trajectory.push_back(data);
        }
      }
      
      file.close();
      
      if (!trajectory.empty()) {
        m_vehicleData[vehicleId] = trajectory;
        NS_LOG_INFO("已加载车辆 " << vehicleId << " 的轨迹数据, 包含 "
                   << trajectory.size() << " 个时间点");
      }
    }
    
    return !m_vehicleData.empty();
    
  } catch (const std::exception& e) {
    NS_LOG_ERROR("加载车辆数据时发生异常: " << e.what());
    return false;
  }
}

bool DataManager::LoadGroundStationData() 
{
  NS_LOG_FUNCTION(this);
  
  std::string filename = m_dataPath + "/ground_stations.csv";
  
  try {
    // 确保文件存在
    if (!fs::exists(filename)) {
      NS_LOG_ERROR("地面基站数据文件不存在: " << filename);
      return false;
    }
    
    std::ifstream file(filename);
    if (!file) {
      NS_LOG_ERROR("无法打开地面基站数据文件: " << filename);
      return false;
    }
    
    std::string line;
    bool isFirstLine = true;
    uint32_t id = 0;
    
    while (std::getline(file, line)) {
      // 跳过注释行和标题行
      if (line.empty() || line[0] == '#' || line[0] == '/' || isFirstLine) {
        isFirstLine = false;
        continue;
      }
      
      std::istringstream iss(line);
      std::string token;
      std::vector<std::string> tokens;
      
      // 分割CSV行
      while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
      }
      
      // 确保有足够的数据列
      if (tokens.size() >= 3) {
        NodePositionData data;
        data.id = id++;
        data.position.x = std::stod(tokens[0]);
        data.position.y = std::stod(tokens[1]);
        data.position.z = std::stod(tokens[2]);
        
        m_groundStationPositions.push_back(data);
      }
    }
    
    file.close();
    
    return !m_groundStationPositions.empty();
    
  } catch (const std::exception& e) {
    NS_LOG_ERROR("加载地面基站数据时发生异常: " << e.what());
    return false;
  }
}

bool DataManager::LoadSatelliteData() 
{
  NS_LOG_FUNCTION(this);
  
  std::string filename = m_dataPath + "/satellites.csv";
  
  try {
    // 确保文件存在
    if (!fs::exists(filename)) {
      NS_LOG_ERROR("卫星数据文件不存在: " << filename);
      return false;
    }
    
    std::ifstream file(filename);
    if (!file) {
      NS_LOG_ERROR("无法打开卫星数据文件: " << filename);
      return false;
    }
    
    std::string line;
    bool isFirstLine = true;
    uint32_t id = 0;
    
    while (std::getline(file, line)) {
      // 跳过注释行和标题行
      if (line.empty() || line[0] == '#' || line[0] == '/' || isFirstLine) {
        isFirstLine = false;
        continue;
      }
      
      std::istringstream iss(line);
      std::string token;
      std::vector<std::string> tokens;
      
      // 分割CSV行
      while (std::getline(iss, token, ',')) {
        tokens.push_back(token);
      }
      
      // 确保有足够的数据列
      if (tokens.size() >= 3) {
        NodePositionData data;
        data.id = id++;
        data.position.x = std::stod(tokens[0]);
        data.position.y = std::stod(tokens[1]);
        data.position.z = std::stod(tokens[2]);
        
        m_satellitePositions.push_back(data);
      }
    }
    
    file.close();
    
    return !m_satellitePositions.empty();
    
  } catch (const std::exception& e) {
    NS_LOG_ERROR("加载卫星数据时发生异常: " << e.what());
    return false;
  }
}

uint32_t DataManager::ParseVehicleId(const std::string& filename) const 
{
  std::regex pattern("vehicle_(\\d+)\\.csv");
  std::smatch matches;
  
  if (std::regex_search(filename, matches, pattern) && matches.size() > 1) {
    return std::stoul(matches[1].str());
  }
  
  return 0;
}

} // namespace ns3
